#!/usr/bin/perl
use strict;
use Data::Dumper;
use FileHandle;
use File::Basename;

my $g_svnst_types = {};

my $g_branch;
my $id = $ENV{'USER'};
my $g_codebase = get_codebase();
my $g_branch   = get_branch();
my $g_qdir   = "/volume/dc-build01-d/QDIR/$g_codebase";

if ($ARGV[0] eq '-ls') {
    my $cmd = "ls -1d $g_qdir/jobs-todo/*/*-$id 2>/dev/null";
    my $myjobs = `$cmd`;
    print $myjobs;
    exit;
}

my $g_user_workdir   = "$g_qdir/$id/$g_branch";
submit();

sub submit
#-----------------------------------------------------------------------
{
    check_are_we_at_root();
    mkdirs();
    log_time();
    # TODO activate these
    #warn_this_will_be_updated();
    #svn_update();
    svn_status();
    punt_if_not_simple();
    collect_sandbox_diff();
    log_time();
}
sub get_codebase
#-----------------------------------------------------------------------
{
    my $svninfo = get_svn_info('.');
    my $svnroot = $svninfo->{'Repository Root'};

    if (0) {
    }
    elsif (
              ($svnroot eq 'https://svn.juniper.net/svn/junos-2009')
           || ($svnroot eq 'https://svl-svn.juniper.net/svn/junos-2009')
           || ($svnroot eq 'https://bng-svn.juniper.net/svn/junos-2009')
           # TODO need to know server name for east coase
          )
    {
        return 'junos';
    }
    elsif (
              ($svnroot eq 'https://svn.juniper.net/svn/qf')
           || ($svnroot eq 'https://svl-svn.juniper.net/svn/qf')
           || ($svnroot eq 'https://bng-svn.juniper.net/svn/qf')
           # TODO need to know server name for east coase
          )
    {
        return 'qf';
    }
}
sub get_branch
#-----------------------------------------------------------------------
{
    my $svninfo = get_svn_info('.');
    return $svninfo->{'branch'};
}
sub check_are_we_at_root
#-----------------------------------------------------------------------
{
    my $svninfo = get_svn_info('.');
    my $url  = $svninfo->{'URL'};
    my $root = $svninfo->{'Repository Root'};
    my $qmroot = quotemeta $root;
    my $rest = $url;
    $rest =~ s/^$qmroot//;
    if (
            ($rest =~ m{^/trunk$})
         || ($rest =~ m{^/branches/[^/]+$})
       )
    {
        # good
    }
    else
    {
        print "\n\nYou are at the root of your sandbox. Aborting.\n\n";
        exit 3;
    }
}
sub warn_this_will_be_updated
#-----------------------------------------------------------------------
{
    print ''
    . "  +----------!!!!!!!!!------WARNING------!!!!!!!!----------+\n"
    . "  |                                                        |\n"
    . "  |      This operation will \"svn update\" your sandbox     |\n"
    . "  |                                                        |\n"
    . "  |               This is quite IRREVERSIBLE               |\n"
    . "  |                                                        |\n"
    . "  +--------------------------------------------------------+\n"
    . "\n"
    . '  Is that OK? (yes/no) : '
    ;
    my $response = <STDIN>;
    chomp $response;
    if (
           ($response eq 'yes')
        || ($response eq 'YES')
       )
    {
    }
    else
    {
        print "\nAll right. Not proceeding. (You didn't say 'yes')\n";
        exit(3);
    }
}
sub mkdirs
#-----------------------------------------------------------------------
{
    my $now = time;
    my ($sec,$min,$hour,$mday,$mon,$year,$wday,$yday,$isdst) =
                                                    localtime($now);
    my $today = sprintf('%04d-%02d-%02d', $year+1900, $mon, $mday);
    $g_user_workdir .= "/$today/$now";
    system "mkdir -p $g_user_workdir/scripts $g_qdir/tmp $g_qdir/jobs-todo";
    system "chmod 777 $g_qdir/tmp $g_qdir/jobs-todo";
    if (!-d $g_user_workdir) {
        print "Error: Could not create dir $g_user_workdir\n";
        exit 3;
    }
    system "echo 'id -a' >>$g_user_workdir/where.txt";
    system "id -a >>$g_user_workdir/where.txt";
    system "echo '--------------------------------------------------' >>$g_user_workdir/where.txt";
    system "echo hostname >>$g_user_workdir/where.txt";
    system "hostname >>$g_user_workdir/where.txt";
    system "echo '--------------------------------------------------' >>$g_user_workdir/where.txt";
    system "echo pwd >>$g_user_workdir/where.txt";
    system "pwd >>$g_user_workdir/where.txt";
    system "echo '--------------------------------------------------' >>$g_user_workdir/where.txt";
    system "echo 'df -kh .' >>$g_user_workdir/where.txt";
    system "df -kh . >>$g_user_workdir/where.txt";
    system "echo '--------------------------------------------------' >>$g_user_workdir/where.txt";
}
sub svn_update
#-----------------------------------------------------------------------
{
    my $svninfo_thisdir = get_svn_info('.');
    my $svninfo_url     = get_svn_info($svninfo_thisdir->{URL});

    if (
         $svninfo_thisdir->{'Last Changed Rev'}
         eq
         $svninfo_url->{'Last Changed Rev'}
       )
    {
        # No update required
        return;
    }

    system "svn up --accept postpone >$g_user_workdir/svnup.log 2>&1";
    system "echo $? >>$g_user_workdir/svnup.log";
}
sub get_svn_info
#-----------------------------------------------------------------------
{
    my $what = shift;
    my @svn_info = `svn info $what`;
    if ($? != 0) {
        print "\n'svn info' failed. Are you sure you are in a subversion sandbox?\n\n";
        exit 2;
    }

    # 0  Path: .
    # 1  URL: https://om-scratch.googlecode.com/svn/trunk/src/sundry
    # 2  Repository Root: https://om-scratch.googlecode.com/svn
    # 3  Repository UUID: 40b42f04-cc1b-a860-77f9-d21a419cf73f
    # 4  Revision: 10
    # 5  Node Kind: directory
    # 6  Schedule: normal
    # 7  Last Changed Author: Om.Mandal@gmail.com
    # 8  Last Changed Rev: 10
    # 9  Last Changed Date: 2011-12-04 17:09:36 -0800 (Sun, 04 Dec 2011)
    my $svn_info = {};
    for my $line (@svn_info) {
        chomp $line;
        my ($key, $value) = $line =~ /^([^:]+)\s*:\s*(.*)$/;
        if ($key ne '') {
            $svn_info->{$key} = $value;
        }
    }
    my $root = $svn_info->{'Repository Root'};
    my $url  = $svn_info->{'URL'};
    my $qmroot = quotemeta $root;
    my ($rest) = $url =~ m/^$qmroot(.*)/;
    $rest =~ s{^/branches}{};
    $rest =~ s{^/}{};
    $rest =~ s{/.*}{};
    $svn_info->{'branch'} = $rest;
    return $svn_info;
}
sub svn_status
#-----------------------------------------------------------------------
{
    system "svn st >$g_user_workdir/svnst.log";
    stsplit("$g_user_workdir/svnst.log", "$g_user_workdir/stsplit");
}
sub stsplit
#-----------------------------------------------------------------------
{
    my ($stlog, $outdir) = @_;
    system "mkdir -p $outdir";
    if (!-d $outdir) {
        print "Error: Could not create '$outdir'\n";
        exit 3;
    }
    open F, "<$stlog" or die;

    my ($type, $file, $fh);
    my $prevline = '';
    while (my $line = <F>) {
        if ($line =~ /^ {6}> {3}(.*)\n/s) {
            $type = $1;
            $type =~ s/ /_/g;
            if(!exists $g_svnst_types->{$type}) {
                $fh = FileHandle->new();
                my $filename = "$outdir/filetype-${type}.txt";
                open $fh, ">$filename" or die;
                $g_svnst_types->{$type}->{'fhandle'} = $fh;
                $g_svnst_types->{$type}->{'fname'} = $filename;
            }
            print {$g_svnst_types->{$type}->{'fhandle'}} $prevline;
        }
        else {
            ($type, $file) = $line =~ /^(.{8})(.*)$/s;
            $type =~ s/ /_/g;
            if(!exists $g_svnst_types->{$type}) {
                $fh = FileHandle->new();
                my $filename = "$outdir/filetype-${type}.txt";
                open $fh, ">$filename" or die;
                $g_svnst_types->{$type}->{'fhandle'} = $fh;
                $g_svnst_types->{$type}->{'fname'} = $filename;
            }
            print {$g_svnst_types->{$type}->{'fhandle'}} $line;
            $prevline = $line;
        }
    }
    close F;

    for my $type (keys %$g_svnst_types) {
        close $g_svnst_types->{$type}->{'fhandle'};
        $g_svnst_types->{$type}->{'fhandle'} = '';
    }
}
sub punt_if_not_simple
#-----------------------------------------------------------------------
{
    open F, "<$g_user_workdir/svnst.log" or die;
    while (my $line  = <F>) {
        if ($line =~ m{^[ ADM\?][ M][ ][ \+][ ][ ][ ][ ]}) {
            # These are simple cases.
            # All these are OK
            # See 'svn status -h' for explanation
        }
        else {
            print "\n"
                . "There are conflicts or missing entries or replaces in your sandbox still.\n"
                . "Please resolve them first and then submit again.\n"
                . "\n";
            system "wc -l $g_user_workdir/stsplit/*";
            exit 1;
        }
    }
    close F;
}
sub collect_sandbox_diff
#-----------------------------------------------------------------------
{
    #print Dumper($g_svnst_types);
    # 'M__+____'
    # 'A_______'
    # '?_______'
    # 'D_______'
    # 'A__+____'
    # 'M_______'


    my $svninfo = get_svn_info('.');
    #print Dumper($svninfo);
    open F, ">$g_user_workdir/scripts/svninfo.txt" or die;
    print F $svninfo->{'branch'} . '@'  . $svninfo->{'Last Changed Rev'};
    print F "\n";
    close F;

    my ($fin, $fout);
    for my $type (keys %$g_svnst_types) {

        if ($type =~ /^XXX/) { # Will never happen
        }
        elsif ($type =~ /^D/) {
            open $fin, '<' . $g_svnst_types->{$type}->{'fname'} or die;
            open $fout,  ">>$g_user_workdir/scripts/dels.txt"  or die;
        }
        elsif ($type =~ /^A/) {
            open $fin, '<' . $g_svnst_types->{$type}->{'fname'} or die;
            open $fout,  ">>$g_user_workdir/scripts/adds.txt"  or die;
        }
        elsif ($type =~ /^M/) {
            open $fin, '<' . $g_svnst_types->{$type}->{'fname'} or die;
            open $fout,  ">>$g_user_workdir/scripts/mods.txt"  or die;
        }
        elsif ($type =~ /^\?/) {
            open $fin, '<' . $g_svnst_types->{$type}->{'fname'} or die;
            open $fout,  ">>$g_user_workdir/scripts/locals.txt"  or die;
        }
        while (my $line = <$fin>) {
            $line =~ s/^........//;
            print $fout $line;
        }
        close $fout;
        close $fin;
    }

    for my $filebase (qw (dels adds mods locals)) {
        my $file = "$g_user_workdir/scripts/${filebase}.txt";
        next unless (-e $file);
        my $file0 = "${file}0";
        open F, "<$file" or die;
        my @files = grep {$_ !~ m{/Makefile\.depend\.}} <F>;
        close F;
        my $deepest = deepest(\@files); # It also chomps the lines
        open F,   ">${file}-deepest"  or die;
        open F0,  ">${file}-deepest0" or die;
        for my $line (@{$deepest}) {
            print F  $line . "\n";
            print F0 $line . chr(0);
        }
        close F;
        close F0;
    }

    if (-e "$g_user_workdir/scripts/adds.txt-deepest0") {
        system "tar --null --exclude .svn -cz -f $g_user_workdir/scripts/adds.tgz -T $g_user_workdir/scripts/adds.txt-deepest0";
    }
    if (-e "$g_user_workdir/scripts/mods.txt-deepest0") {
        system "tar --null --exclude .svn -cz -f $g_user_workdir/scripts/mods.tgz -T $g_user_workdir/scripts/mods.txt-deepest0";
    }

    open SCRIPT, ">$g_user_workdir/scripts/script.sh" or die;
    print SCRIPT  ''
                . '#!/bin/sh' . "\n"
                . '' . "\n"
                . 'd=`dirname $0`' . "\n"
                . '' . "\n"
                ;
    if (-e "$g_user_workdir/scripts/dels.txt-deepest0") {
        print SCRIPT 'cat $d/dels.txt-deepest0 | xargs -0 -L 100 svn rm' . "\n";
    }
    if (-e "$g_user_workdir/scripts/adds.tgz") {
        print SCRIPT 'tar xfz $d/adds.tgz' . "\n";
    }
    if (-e "$g_user_workdir/scripts/mods.tgz") {
        print SCRIPT 'tar xfz $d/mods.tgz' . "\n"
    }
    if (-e "$g_user_workdir/scripts/locals.txt-deepest0") {
        print SCRIPT 'cat $d/locals.txt-deepest0 | xargs -0 -L 100 /bin/rm -rf' . "\n";
    }
    if (-e "$g_user_workdir/scripts/adds.txt-deepest0") {
        print SCRIPT 'cat $d/adds.txt-deepest0 | xargs -0 -L 100 svn add --parents' . "\n";
    }
    close SCRIPT;

    my $job = basename($g_user_workdir);
    system "cp -pr $g_user_workdir $g_qdir/tmp/$job-$id";
    system "chmod 777 $g_qdir/tmp/$job-$id";

    my $branch = $svninfo->{'branch'};
    system "mkdir -p $g_qdir/jobs-todo/$branch";
    system "chmod 777 $g_qdir/jobs-todo/$branch";
    system "mv $g_qdir/tmp/$job-$id $g_qdir/jobs-todo/$branch/$job-$id";
    system "chmod 777 $g_qdir/jobs-todo/$branch/$job-$id";
    # TODO activate chmod
    #system "chmod 000 .";
    print_advisory("$g_qdir/jobs-todo/$branch/$job-$id");
}
sub deepest
#-----------------------------------------------------------------------
{
    my $files = shift;
    my $deepest = [];
    my @lines = sort map {chomp; $_ =~ s{/$}{}; $_} @{$files};
    my $qmprintedline = '';
    for my $line (@lines) {
        if ($line =~ m{^$qmprintedline/.+$}) {  # If new line contains the previous line
            # Don't print anything
        }
        else {
            push @{$deepest}, $line;
            $qmprintedline = quotemeta $line;
        }
    }
    return $deepest;
}
sub print_advisory
#-----------------------------------------------------------------------
{
    my $job = shift;
    print <<"EOF";

FAKE TEXT BELOW. PAY NO ATTENTION

You commit job is successfully submitted

$job


I also did 'chmod 000' on your current directory
to encourage you to not modify it further. You will
need this sandbox for committing these changes when
your changes are verified by Daily Sanity.



EOF
}
sub log_time
{
    open F, ">>$g_user_workdir/timestamp.txt" or die;
    print F localtime(time) . "\n";
    close F;
}









